from csv import writer as csvWriter
from time import time as now
from re import findall as findPlayers
from re import split as getTeamID
from time import strptime as parseTime
from calendar import timegm as getTimestamp

input_file = "./match2.txt"
output_file = "./match2.csv"

stats_5 = 9
stats_6 = 10
stats_7 = 11
stats_8 = 12
stats_9 = 13
stats_10 = 14
stats_11 = 15
stats_12 = 16
stats_13 = 17
stats_14 = 18
stats_hit_broadcasted = 7
stats_max_hits_short = 8
stats_hits = 19
stats_hits_short = 21
stats_last_hit = 20
stats_death = 3
stats_kill = 2
stats_team = 1
stats_actor_p_main = 5
stats_actor_p_scnd = 6
stats_score = 4
stats_max_index = 21
stats_max_index_printable = 18

stats_first_row = ["ID","队伍ID","击败人数","阵亡次数","总得分","常用角色","次要常用角色","连击广播总数","短时最高连击","五连击","六连击","七连击","八连击","九连击","十连击","十一连击","十二连击","十三连击","十四连击","保留"]

weapons = ["喵的末路","圣剑","角斗士的终幕礼","翡翠之弩","末日拳套","猎杀者匕首 | (★)","埃提耶什","光明权杖","PRTS 代理作战终端","羽毛笔"]
professions = ["毛妹","吉塔","大锤","全藏","铁拳","刺客","麦迪文","天使","刀客塔","羽毛笔"]

# 假定制造11~12连击得分为5
points = [1,1,1,2,2,2,3,3,4,4,5,5]


class Stats():
  players = {}
  actors = []

  def __init__(self) -> None:
      i = 0
      while(i<len(weapons)):
        p_count = {}
        self.actors.append(p_count)
        i+=1
      pass

  def create(self,player_team_id):
    pid=player_team_id[1]
    team=player_team_id[0].strip('[]')
    player = []
    player.append(pid)
    player.append(team)
    for i in range(2,stats_max_index+1):
      if (i==stats_actor_p_main) or (i==stats_actor_p_scnd) or (i==stats_last_hit):
        player.append("无")
      else:
        player.append(0)
    self.players[pid]=player
    
  def death(self,player_team_id,gg=False):
    pid=player_team_id[1]
    if(pid not in self.players):
      self.create(player_team_id)
    player=self.players[pid]
    # 阵亡/比赛结束时，归结短时连击次数
    if(player[stats_max_hits_short]<player[stats_hits_short]):
      player[stats_max_hits_short]=player[stats_hits_short]
    player[stats_hits_short]=0
    # 阵亡/比赛结束时，归结本轮连击杀敌数
    i = player[stats_hits]
    if (i>=5):
      player[stats_5+i-5] += 1
    player[stats_hits]=0
    
    if (gg==False):
      # 比赛期间计算阵亡数
      player[stats_death]+=1
    else:
      # 比赛结束时，归结最常用的两个职业
      j=0
      p1=len(professions)+1
      p2=p1
      pc1=0
      pc2=0
      for actor in self.actors:
        if(pid in actor):
          if (pc1<actor[pid]):
            p2 = p1
            p1 = j
            pc2 = pc1
            pc1 = actor[pid]
          elif (pc2<actor[pid]) and (p1!=j):
            pc2 = actor[pid]
            p2 = j
        j+=1
      if (p1==len(professions)+1):
        player[stats_actor_p_main]='N/A'
      else:
        player[stats_actor_p_main]=professions[p1]
      if (p2==len(professions)+1):
        player[stats_actor_p_scnd]='N/A'
      else:
        player[stats_actor_p_scnd]=professions[p2]


  def kill(self,player_team_id,weapon,time):
    pid=player_team_id[1]
    if(pid not in self.players):
      self.create(player_team_id)
    player=self.players[pid]
    # 统计击杀得分
    i = player[stats_hits]
    if (i>=12):
      i=11
    player[stats_score] += points[i]
    if (weapon in weapons):
      # 统计使用武器次数，以确定常用职业
      i = weapons.index(weapon)
      p_count = self.actors[i]
      if (pid not in p_count):
        p_count[pid] = 1
      else:
        p_count[pid] += 1
    # 统计总杀敌数，与本轮连击杀敌数
    player[stats_hits] += 1
    player[stats_kill] += 1
    if(player[stats_hits]>=5):
      player[stats_hit_broadcasted] +=1
    # 统计短时连击数
    now = parseTime(time,'%H:%M:%S')
    if(player[stats_last_hit]!='无'):
      before = parseTime(player[stats_last_hit],'%H:%M:%S')
      now_stamp = getTimestamp(now)
      before_stamp = getTimestamp(before)
      if(now_stamp-before_stamp<=10):
        player[stats_hits_short]+=1
      else:
        if(player[stats_max_hits_short]<player[stats_hits_short]):
          player[stats_max_hits_short]=player[stats_hits_short]
        player[stats_hits_short]=1
    else:
      player[stats_hits_short]=1
    player[stats_last_hit]=time


class LogHandler():
  stats = Stats()
  battle_count = 0
  multihit_broadcast = 0
  shortly_multihit_broadcast = 0

  def __init__(self) -> None:
      pass

  def parseLine(self,line):
    # 必须匹配到一个或两个“[队伍ID] 玩家ID”
    players = findPlayers("\[[0-9]{1,2}\]\s[A-Za-z0-9_]+",line)
    if(len(players)==0) or (len(players)>=3):
      return
    self.battle_count+=1
    if(len(players)==2):
      # 获得玩家ID及其队伍
      player1 = getTeamID('\s',players[0])
      player2 = getTeamID('\s',players[1])
      # 一条“A被B用[武器]击败了”等有两名玩家的消息
      self.stats.death(player1)
      weapon = "无"
      w1 = line.rfind('[')
      w2 = line.rfind(']')
      if(w1>=40) and (w2>=40) and (line[w1+1:w2].isdigit()==False):
        weapon = line[w1+1:w2]
      # 匹配本消息的时间（借用了re.findall的某别名）
      this_time = findPlayers('[0-9]{2}:[0-9]{2}:[0-9]{2}',line)[0]
      self.stats.kill(player2,weapon,this_time)
    else:
      # 一条仅含一名玩家的消息，包括“A掉出了世界”“A被闪电击中”等
      player = getTeamID('\s',players[0])
      # 如果该消息为“连续击败”……统计广播次数
      if(line.find('续击')>=0) or (line.find('败更')>=0):
        self.multihit_broadcast+=1
        return
      # 如果该消息为“双杀！”“三杀！”……略过
      if(line.rfind('杀！')>=0):
        self.shortly_multihit_broadcast+=1
        return
      # 除以上情况外，皆视为阵亡
      self.stats.death(player)

  def goodGame(self):
    print('Record battle events:',self.battle_count)
    print('including multi-hit broadcasts in total of',self.multihit_broadcast)
    print('and shortly multi-hit broadcasts in total of',self.shortly_multihit_broadcast)
    print('Participants count:',len(self.stats.players.keys()))
    for player in self.stats.players.keys():
      player_team_id = ['0',player]
      self.stats.death(player_team_id,True)

  def parseFile(self,path):
    with open(path,'r',encoding='utf-8') as f:
      lines = f.readlines()
      print('Read lines',len(lines))
      for line in lines:
        self.parseLine(line)
      self.goodGame()
      f.close()
    csv_file = open(output_file,'w',newline='',encoding='gb18030')
    writer = csvWriter(csv_file)
    row_to_print = stats_first_row[:stats_max_index_printable+1]
    writer.writerow(row_to_print)
    for row in self.stats.players.values():
      row_to_print = row[:stats_max_index_printable+1]
      writer.writerow(row_to_print)
    csv_file.close()

if __name__=='__main__':
  h = LogHandler()
  time_start = now()
  h.parseFile(input_file)
  time_end = now()
  ellapse = time_end-time_start
  print("It took",ellapse,"sec to run")